<template>
  <div>
    <el-container>
      <el-main>
        <el-row type="flex" justify="center">
          <el-col :span="17">
            <el-col :span="20">
              <div class="content">
                <div class="contentInfo">
                  <img src="../../assets/logo.png" alt="" />
                  <span>小武&nbsp;&nbsp;</span>
                  <span>20 9月</span>
                </div>
                <div class="contentArticle" v-html="compiledMarkdown"></div>
              </div>
            </el-col>
            <el-col :span="4" class="catalog">
              <h2>目录</h2>
              <br />
              <ul>
                <li
                  v-for="(nav, index) in navList"
                  :key="index"
                  :class="{ on: activeIndex === index }"
                  @click="currentClick(index)"
                >
                  <a href="javascript:;" @click="pageJump(nav.index)">{{
                    nav.title
                  }}</a>
                  <div
                    v-if="nav.children.length > 0"
                    class="menu-children-list"
                  >
                    <ul class="nav-list">
                      <li
                        v-for="(item, idx) in nav.children"
                        :key="idx"
                        :class="{ on: childrenActiveIndex === idx }"
                        @click.stop="childrenCurrentClick(idx)"
                      >
                        <a href="javascript:;" @click="pageJump(item.index)">{{
                          item.title
                        }}</a>
                      </li>
                    </ul>
                  </div>
                </li>
              </ul>
            </el-col>
          </el-col>
        </el-row>
      </el-main>
    </el-container>
  </div>
</template>

<script>
import marked from "marked";
import hljs from "highlightjs";
import "highlightjs/styles/monokai-sublime.css";
const highlightCode = () => {
  const preEl = document.querySelectorAll("pre");
  preEl.forEach((el) => {
    hljs.highlightBlock(el);
  });
};
let rendererMD = new marked.Renderer();
marked.setOptions({
  renderer: rendererMD,
  gfm: true,
  tables: true,
  breaks: false,
  pedantic: false,
  sanitize: false,
  smartLists: true,
  smartypants: false,
});
export default {
  data() {
    return {
      article: "",
      html: "", //文章内容
      navList: [],
      activeIndex: 0,
      docsFirstLevels: [],
      docsSecondLevels: [],
      childrenActiveIndex: 0,
    };
  },
  created() {},
  updated() {
    highlightCode();
  },
  mounted() {
    this.getArticleDetail();
  },
  methods: {
    async getArticleDetail() {
      try {
        let id = this.$route.params.id;
        const res = await this.$axios.post("/getOneArticle", { _id: id });
        this.article = res.data.data.content;
        this.html = this.article;
      } catch (e) {
        global.console.log("文章获取异常");
      }
      //文章内容获取后渲染目录，避免目录无法及时获取内容
      this.navList = this.handleNavTree();
      this.getDocsFirstLevels(0);
    },
    childrenCurrentClick(index) {
      this.childrenActiveIndex = index;
    },
    getDocsFirstLevels(times) {
      // 解决图片加载会影响高度问题
      setTimeout(() => {
        let firstLevels = [];
        Array.from(document.querySelectorAll("h3"), (element) => {
          firstLevels.push(element.offsetTop - 60);
        });
        this.docsFirstLevels = firstLevels;

        if (times < 8) {
          this.getDocsFirstLevels(times + 1);
        }
      }, 500);
    },
    getDocsSecondLevels(parentActiveIndex) {
      let idx = parentActiveIndex;
      let secondLevels = [];
      let navChildren = this.navList[idx].children;

      if (navChildren.length > 0) {
        secondLevels = navChildren.map((item) => {
          return this.$el.querySelector(`#data-${item.index}`).offsetTop - 60;
        });
        this.docsSecondLevels = secondLevels;
      }
    },
    getLevelActiveIndex(scrollTop, docsLevels) {
      let currentIdx = null;
      let nowActive = docsLevels.some((currentValue, index) => {
        if (currentValue >= scrollTop) {
          currentIdx = index;
          return true;
        }
      });

      currentIdx = currentIdx - 1;

      if (nowActive && currentIdx === -1) {
        currentIdx = 0;
      } else if (!nowActive && currentIdx === -1) {
        currentIdx = docsLevels.length - 1;
      }
      return currentIdx;
    },
    pageJump(id) {
      this.titleClickScroll = true;
      document.querySelector(`#data-${id}`).scrollIntoView();
      setTimeout(() => (this.titleClickScroll = false), 100);
    },
    currentClick(index) {
      this.activeIndex = index;
      this.getDocsSecondLevels(index);
    },
    getTitle(content) {
      let nav = [];

      let tempArr = [];
      content.replace(/(#+)[^#][^\n]*?(?:\n)/g, function(match, m1) {
        let title = match.replace("\n", "");
        let level = m1.length;
        tempArr.push({
          title: title.replace(/^#+/, "").replace(/\([^)]*?\)/, ""),
          level: level,
          children: [],
        });
      });

      // 只处理二级到四级标题，以及添加与id对应的index值，这里还是有点bug,因为某些code里面的注释可能有多个井号
      nav = tempArr.filter((item) => item.level >= 2 && item.level <= 4);
      let index = 0;
      return (nav = nav.map((item) => {
        item.index = index++;
        return item;
      }));
    },
    // 将一级二级标题数据处理成树结构
    handleNavTree() {
      let navs = this.getTitle(this.content);
      let navLevel = [3, 4];
      let retNavs = [];
      let toAppendNavList;

      navLevel.forEach((level) => {
        // 遍历一级二级标题，将同一级的标题组成新数组
        toAppendNavList = this.find(navs, {
          level: level,
        });

        if (retNavs.length === 0) {
          // 处理一级标题
          retNavs = retNavs.concat(toAppendNavList);
        } else {
          // 处理二级标题，并将二级标题添加到对应的父级标题的children中
          toAppendNavList.forEach((item) => {
            item = Object.assign(item);
            let parentNavIndex = this.getParentIndex(navs, item.index);
            return this.appendToParentNav(retNavs, parentNavIndex, item);
          });
        }
      });
      return retNavs;
    },
    find(arr, condition) {
      return arr.filter((item) => {
        for (let key in condition) {
          if (condition.hasOwnProperty(key) && condition[key] !== item[key]) {
            return false;
          }
        }
        return true;
      });
    },
    getParentIndex(nav, endIndex) {
      for (var i = endIndex - 1; i >= 0; i--) {
        if (nav[endIndex].level > nav[i].level) {
          return nav[i].index;
        }
      }
    },
    appendToParentNav(nav, parentIndex, newNav) {
      let index = this.findIndex(nav, {
        index: parentIndex,
      });
      if (nav[index]) {
        nav[index].children = nav[index].children.concat(newNav);
      }
    },
    findIndex(arr, condition) {
      let ret = -1;
      arr.forEach((item, index) => {
        for (var key in condition) {
          if (condition.hasOwnProperty(key) && condition[key] !== item[key]) {
            return false;
          }
        }
        ret = index;
      });
      return ret;
    },
  },
  computed: {
    content() {
      return this.html;
    },
    //此函数将markdown内容进一步的转换
    compiledMarkdown: function() {
      let index = 0;
      rendererMD.heading = function(text, level) {
        //我比较习惯三级和四级目录，这里看你喜欢
        if (level <= 4) {
          return `<h${level} id="data-${index++}">${text}</h${level}>`;
        } else {
          return `<h${level}>${text}</h${level}>`;
        }
      };
      return marked(this.content);
    },
  }
};
</script>

<style lang="less">
.content {
  padding: 20px;
  padding-left: 0;
  .contentInfo {
    img {
      width: 30px;
    }
  }
  .contentArticle {
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
    font-size: 14px;
    overflow: auto;
    background-color: #e9e6f4;
    h1 {
      font-size: 30px;
    }
    h2 {
      font-size: 28px;
      border-bottom: 1px solid #cbcbcb;
    }
    h3 {
      font-size: 24px;
    }
    pre {
      display: block;
      background-color: #f3f3f3;
      padding: 0.5rem !important;
      overflow-y: auto;
      font-weight: 300;
      font-family: Menlo, monospace;
      border-radius: 0.3rem;
    }
    pre {
      background-color: #283646 !important;
    }
    pre > code {
      border: 0px !important;
      background-color: #283646 !important;
      color: #fff;
    }
    code {
      display: inline-block;
      background-color: #f3f3f3;
      border: 2px solid #fdb9cc;
      border-radius: 3px;
      font-size: 12px;
      padding-left: 5px;
      padding-right: 5px;
      color: #4f4f4f;
      margin: 0px 3px;
    }
  }
}
.catalog {
  padding: 20px;
  font-size: 14px;
  position: fixed;
  top: 15%;
  right: 10%;
  background: url("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=726779025,3976052498&fm=26&gp=0.jpg");
  background-size: cover;
  border-radius: 10px;
  height: 600px;
  overflow-y: scroll;
  ul {
    li {
      a {
        color: black;
        &:active {
          color: blue;
        }
      }
    }
  }
  .menu-children-list {
    padding-left: 20px;
    font-size: 10px;
    white-space: pre-wrap;
  }
}
</style>
